package com.beidouin.GnssMain.models;

import android.location.GpsSatellite;
import android.location.LocationManager;

import java.util.Arrays;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;

/**
 * Created by yuyang on 16/6/23.
 */
public class BeidouStatus {

    protected final String TAG = this.getClass().getName() + "@" + this.hashCode();
    private static int NUM_SATELLITES = 0;
    private int nSatellitesRecv = 0;
    private static BeidouStatus sInstance = new BeidouStatus();

    /* These package private values are modified by the LocationManager class */
    private int mTimeToFirstFix;
    private BeidouSatellite mSatellites[];

    public static BeidouStatus getInstance() {
        return sInstance;
    }

    public BeidouStatus() {
        mSatellites = new BeidouSatellite[NUM_SATELLITES];
    }

    public void setData(HashMap<Integer, BeidouSatellite> beidouMap) {
        if (beidouMap.size() == 0) return;
        NUM_SATELLITES = beidouMap.size();
        mSatellites = new BeidouSatellite[NUM_SATELLITES];
        int i = 0;
        for (Map.Entry<Integer, BeidouSatellite> entry : beidouMap.entrySet()) {
            mSatellites[i] = entry.getValue();
            i++;
        }

    }

    private final class SatelliteIterator implements Iterator<BeidouSatellite> {

        private BeidouSatellite[] mSatellites;
        int mIndex = 0;

        SatelliteIterator(BeidouSatellite[] satellites) {
            mSatellites = satellites;
        }

        public int getSize() {
            return mSatellites.length;
        }

        public boolean hasNext() {
            for (int i = mIndex; i < mSatellites.length; i++) {
//                if (mSatellites[i].mValid) {
                return true;
//                }
            }
            return false;
        }

        public BeidouSatellite next() {
            while (mIndex < mSatellites.length) {
                BeidouSatellite satellite = mSatellites[mIndex++];
//                if (satellite.mValid) {
                return satellite;
//                }
            }
            throw new NoSuchElementException();
        }

        public void remove() {
            throw new UnsupportedOperationException();
        }
    }

    private Iterable<BeidouSatellite> mSatelliteList = new Iterable<BeidouSatellite>() {
        public Iterator<BeidouSatellite> iterator() {
            return new SatelliteIterator(mSatellites);
        }
    };

    /**
     * Used internally within {@link LocationManager} to copy GPS status
     * data from the Location Manager Service to its cached GpsStatus instance.
     * Is synchronized to ensure that GPS status updates are atomic.
     */
    synchronized void setStatus(int svCount, int[] prns, int[] snrs,
                                int[] elevations, int[] azimuths, int ephemerisMask,
                                int almanacMask, int usedInFixMask) {
        int i;

        for (i = 0; i < svCount; i++) {
            int id = prns[i] - 1;
            int prnShift = (1 << id);
            if (id >= 0 && id < mSatellites.length) {
                BeidouSatellite satellite = mSatellites[id];

                satellite.mSnr = snrs[i];
                satellite.mElevation = elevations[i];
                satellite.mAzimuth = azimuths[i];

            }
        }
    }

    /**
     * Used by {@link LocationManager#getGpsStatus} to copy LocationManager's
     * cached GpsStatus instance to the client's copy.
     * Since this method is only used within {@link LocationManager#getGpsStatus},
     * it does not need to be synchronized.
     */
    void setStatus(BeidouStatus status) {
        mTimeToFirstFix = status.getTimeToFirstFix();

        for (int i = 0; i < mSatellites.length; i++) {
            mSatellites[i].setStatus(status.mSatellites[i]);
        }
    }

    void setTimeToFirstFix(int ttff) {
        mTimeToFirstFix = ttff;
    }

    /**
     * Returns the time required to receive the first fix since the most recent
     * restart of the GPS engine.
     *
     * @return time to first fix in milliseconds
     */
    public int getTimeToFirstFix() {
        return mTimeToFirstFix;
    }

    /**
     * Returns an array of {@link GpsSatellite} objects, which represent the
     * current state of the GPS engine.
     *
     * @return the list of satellites
     */
    public Iterable<BeidouSatellite> getSatellites() {
        return mSatelliteList;
    }

    public List<BeidouSatellite> getSatellitesList() {
        Comparator cmp = new MyComparator();
        Arrays.sort(mSatellites, cmp);
        return Arrays.asList(mSatellites);

    }
    /**
     * Returns the maximum number of satellites that can be in the satellite
     * list that can be returned by {@link #getSatellites()}.
     *
     * @return the maximum number of satellites
     */
    public int getMaxSatellites() {
        return NUM_SATELLITES;
    }
}


class MyComparator implements Comparator<BeidouSatellite> {
    @Override
    public int compare(BeidouSatellite o1, BeidouSatellite o2) {
        //如果n1小于n2，我们就返回正值，如果n1大于n2我们就返回负值，
        //这样颠倒一下，就可以实现反向排序了

        if (o1.getSateType() == BeidouSatellite.SATE_BEIDOU && o2.getSateType() != BeidouSatellite.SATE_BEIDOU) {
            return -1;
        } else if (o1.getSateType() != BeidouSatellite.SATE_BEIDOU && o2.getSateType() == BeidouSatellite.SATE_BEIDOU) {
            return 1;
        } else if (o1.getSateType() < o2.getSateType()) {
            return -1;
        } else if (o1.getSateType() > o2.getSateType()) {
            return 1;
        } else if (o1.getMsvId() < o2.getMsvId()) {
            return -1;
        } else if (o1.getMsvId() > o2.getMsvId()) {
            return 1;
        } else {
            return 0;
        }
    }
}